﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using SymbolicComputation;
using Microsoft.VisualBasic;
using System.Diagnostics;
using FileHelper;
namespace Sym
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public FileIO<AppData> pubFileIO = new FileIO<AppData>();
        public Double opacity = .85;
        public MainWindow()
        {
            InitializeComponent();
            Init();
        }

        public void Init()
        {
            NewTab(false, "Tab 1");
            this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
            InitializeTransformTabs();
            tabControl1.Opacity = opacity;
            tabControl2.Opacity = opacity;
            this.txtActiveTransform.Opacity = opacity;
            pubFileIO.Filter = "Symbolic Computation Application Files (*.sca)|*.sca";
        }

        public void InitializeTransformTabs()
        {
            List<String> transforms = TransformSets.AllAsSets();
            NewTransformTab(false, "Commutative");
            TransformTabTextBox(0).Text = transforms[0];
            NewTransformTab(false, "Distributive");
            TransformTabTextBox(1).Text = transforms[1];
            NewTransformTab(false, "Elementary");
            TransformTabTextBox(2).Text = transforms[2];
            NewTransformTab(false, "Simplifying");
            TransformTabTextBox(3).Text = transforms[3];
            NewTransformTab(false, "Exponential");
            TransformTabTextBox(4).Text = transforms[4];
            //NewTransformTab(false, "Trigonometric");
            //TransformTabTextBox(5).Text = transforms[5];
            //NewTransformTab(false, "Derivates");
            //TransformTabTextBox(6).Text = transforms[6];
            this.tabControl2.SelectedIndex = 0;
        }

        void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            MessageBoxResult result= MessageBox.Show("Do you want to save the open file before closing?", "Save?", MessageBoxButton.YesNoCancel);
            if (result == MessageBoxResult.Yes)
            {
                AppData appData = InterfaceToAppData();
                pubFileIO.SaveAs(ref appData);
            }
            else if (result == MessageBoxResult.Cancel)
            {
                e.Cancel = true;
            }
        }

        private void FileNew_Click(object sender, RoutedEventArgs e)
        {
            AppDataToInterface(new AppData());
        }

        private void FileOpen_Click(object sender, RoutedEventArgs e)
        {
            AppData appData = new AppData();
            pubFileIO.Open(ref appData);
            Functional.ActionMaps.Map<ScFile>(appData.openFiles, x => x.text = SetToEnvironmentNewLine(x.text));
            Functional.ActionMaps.Map<ScFile>(appData.transformPages, x => x.text = SetToEnvironmentNewLine(x.text));
            AppDataToInterface(appData);
        }

        public static String SetToEnvironmentNewLine(String inSetMe)
        {
            String text = inSetMe.Replace(Environment.NewLine, "\n");
            text = text.Replace("\r", "\n");
            text = text.Replace("\n", Environment.NewLine);
            return text;
        }

        private void FileSave_Click(object sender, RoutedEventArgs e)
        {
            AppData appData=InterfaceToAppData();
            pubFileIO.Save(ref appData);
        }

        private void FileSaveAs_Click(object sender, RoutedEventArgs e)
        {
            AppData appData = InterfaceToAppData();
            pubFileIO.SaveAs(ref appData);
        }

        private void FileQuit_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        public void PutTextInTextBox(String putMe,Boolean insertIntoSelected=true)
        {
            putMe = Miscellaneous.RemoveDSuffixesFromEquation(putMe);
            TextBox textBox = SelectedTabTextBox;
            if (insertIntoSelected == true)
            {
                if (textBox.SelectionLength > 0)
                {
                    textBox.SelectedText = putMe;
                }
                else
                {
                    AddStringToSelectedTabText(putMe);
                }
            }
            else
            {
                AddStringToSelectedTabText(putMe);
            }
        }

        private void btnEvaluate_Click(object sender, RoutedEventArgs e)
        {
            Evaluate();
        }

        public void Evaluate()
        {
            String selectedText = this.GetSelectedTextOrLine();
            if (selectedText == "" | selectedText == null)
            {
                return;
            }
            String result = RoslynEval.ScriptEval.Evaluate(selectedText).ToString();
            PutTextInTextBox(result);
        }

        public String GetSelectedTextOrLine(Boolean noSelected=false,Boolean noDSuffixes=false)
        {
            TextBox textBox = SelectedTabTextBox;
            return this.GetSelectedTextOrLine(ref textBox,noSelected,noDSuffixes);
        }

        public String GetSelectedTextOrLine(ref TextBox inTextBox,Boolean noSelected=false,Boolean noDSuffixes=false)
        {
            String text = "";
            if (noSelected == false)
            {
                text = inTextBox.SelectedText;
            }
            if (text == "")
            {
                text=GetLine(ref inTextBox);
            }
            if (noDSuffixes == false)
            {
                text = Miscellaneous.AddDSuffixesToEquation(text);
            }
            text = Miscellaneous.ConvertToDoubleEqualSigns(text);
            return text;
        }

        public String GetLine(ref TextBox inTextBox)
        {
            String text = inTextBox.Text;
            Int32 cursorPosition = inTextBox.SelectionStart;
            Int32 end = Miscellaneous.SearchForEndForwards(text, Environment.NewLine, cursorPosition);
            Int32 begin = Miscellaneous.SearchForEndBackwards(text, Environment.NewLine, cursorPosition);
            String selectedLineText = text.Substring(begin, end - begin);
            return selectedLineText;
        }

        public void AddStringToSelectedTabText(String addMe)
        {
            SelectedTabString = SelectedTabString + Environment.NewLine + addMe;
            SelectedTextBox.Select(SelectedTextBox.Text.Length, 0);
            SelectedTextBox.SelectionStart = SelectedTextBox.Text.Length;
            SelectedTextBox.CaretIndex = SelectedTextBox.Text.Length;
            SelectedTextBox.Focus();
        }

        private void btnTransform_Click(object sender, RoutedEventArgs e)
        {
            Transform();
        }

        public void Transform()
        {
            String transformMe = this.GetSelectedTextOrLine();
            if (transformMe == "" | transformMe == null)
            {
                return;
            }
            String transformString = this.txtActiveTransform.Text;
            if (transformString == "" | transformString == null)
            {
                return;
            }
            String transformedResult = SymbolicComputation.AlgebraTransform.TransformAlgebraicString(transformMe, transformString);
            PutTextInTextBox(transformedResult);
        }

        private void btnIsolateVariable_Click(object sender, RoutedEventArgs e)
        {
            String isolateMe = Microsoft.VisualBasic.Interaction.InputBox("Enter the variable you want to isolate.");
            
        }

        public void Isolate(String isolateMe)
        {
            if (isolateMe == null | isolateMe == "")
            {
                return;
            }
            isolateMe = Miscellaneous.AddDSuffixesToEquation(isolateMe);
            //String equation = this.GetSelectedTextOrLine();
            String equation = this.GetSelectedTextOrLine(true);
            if (equation == "" | equation == null)
            {
                return;
            }
            List<String> transformStrings = Transforms().ToList();
            SymbolicComputation.IsolateSingleVariable worker = new SymbolicComputation.IsolateSingleVariable();
            String result = worker.Isolate(equation, isolateMe);
            PutTextInTextBox(result, false);
        }

        private void HelpAbout_Click(object sender, RoutedEventArgs e)
        {
            About lAbout = new About();
            lAbout.ShowDialog();
        }

        private void mnuTabDelete_Click(object sender, RoutedEventArgs e)
        {
            MessageBoxResult result = MessageBox.Show("Are you sure you want to delete the current tab?", "Delete?", MessageBoxButton.OKCancel);
            if (result == MessageBoxResult.OK)
            {
                if (tabControl1.SelectedIndex > -1)
                {
                    tabControl1.Items.RemoveAt(tabControl1.SelectedIndex);
                }
            }
        }

        private void mnuTabNew_Click(object sender, RoutedEventArgs e)
        {
            NewTab(true,this.tabControl1,"");
        }

        public void NewTab(Boolean nameTab,String tabName)
        {
            NewTab(nameTab, this.tabControl1,tabName);
        }

        public void NewTransformTab(Boolean nameTab,String tabName)
        {
            NewTab(nameTab, this.tabControl2,tabName);
            TextBox lBox = SelectedTabsTextBox(this.tabControl2);
            lBox.MouseDoubleClick += new MouseButtonEventHandler(lBox_MouseDoubleClick);
        }

        public void NewTab(Boolean nameTab,TabControl tabControl,String tabName)
        {
            if (nameTab == true)
            {
                 tabName = Interaction.InputBox("Enter a name for the new tab.","Enter Name","Tab " + Convert.ToString(tabControl.Items.Count+1));
                 if (tabName=="" | tabName=="")
                 {
                     return;
                 }
            }
            else if (tabName !="" & tabName !=null)
            {
                //tabName = tabName;
            }
            else
            {
                tabName = "Tab " + Convert.ToString(tabControl.SelectedIndex + 1);
            }
            TabItem lTab = new TabItem();
            TextBox lBox = new TextBox();
            lBox.Opacity = opacity;
            lBox.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
            lBox.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
            lBox.FontSize = 22;
            lBox.AcceptsReturn=true;
            lTab.Content = (object)lBox;
            tabControl.Items.Add(lTab);
            tabControl.SelectedIndex = tabControl.Items.Count - 1;
            lTab.Header = tabName;
        }

        void lBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            TextBox textBox = SelectedTransformTabTextBox;
            String transform = GetLine(ref textBox);
            this.txtActiveTransform.Text = transform;
        }

        public TabItem SelectedTransformTab
        {
            get
            {
                return (TabItem)this.tabControl2.SelectedItem;
            }
        }

        public TabItem SelectedTab
        {
            get
            {
                return (TabItem)this.tabControl1.SelectedItem;
            }
        }

        public static TabItem SelectedTabItem(TabControl tabControl)
        {
            return (TabItem)tabControl.SelectedItem;
        }

        public static TextBox SelectedTabsTextBox(TabControl tabControl)
        {
            return (TextBox)SelectedTabItem(tabControl).Content;
        }

        public TextBox SelectedTabTextBox
        {
            get
            {
                return (TextBox)SelectedTab.Content;
            }
        }

        public TextBox SelectedTransformTabTextBox
        {
            get
            {
                return (TextBox)SelectedTransformTab.Content;
            }
        }

        public TextBox TransformTabTextBox(Int32 tabIndex)
        {
            TabItem tab = (TabItem)this.tabControl2.Items[tabIndex];
            return (TextBox)tab.Content;
        }

        public String SelectedTabString
        {
            get
            {
                return SelectedTextBox.Text;
            }
            set
            {
                SelectedTextBox.Text=value;
            }
        }

        public TextBox SelectedTextBox
        {
            get
            {
                return (TextBox)SelectedTab.Content;
            }
        }

        public AppData InterfaceToAppData()
        {
            Int32 L;
            TextBox lBox;
            TabItem lTab;
            AppData lOut = new AppData();
            for (L = 0; L < this.tabControl1.Items.Count; L++)
            {
                lTab = (TabItem)this.tabControl1.Items[L];
                lBox= (TextBox)lTab.Content;
                lOut.openFiles.Add(new ScFile());
                lOut.openFiles[L].text = lBox.Text;
                lOut.openFiles[L].name = (String)lTab.Header;
            }
            for (L = 0; L < this.tabControl2.Items.Count; L++)
            {
                lTab = (TabItem)this.tabControl2.Items[L];
                lBox = (TextBox)lTab.Content;
                lOut.transformPages.Add(new ScFile());
                lOut.transformPages[L].text = lBox.Text;
                lOut.transformPages[L].name = (String)lTab.Header;
            }
            return lOut;
        }

        public void AppDataToInterface(AppData inAppData)
        {
            Int32 L;
            this.tabControl1.Items.Clear();
            this.tabControl2.Items.Clear();
            for (L = 0; L < inAppData.openFiles.Count; L++)
            {
                NewTab(false,"");
                SelectedTab.Header = inAppData.openFiles[L].name;
                SelectedTextBox.Text = inAppData.openFiles[L].text;
            }
            for (L = 0; L < inAppData.transformPages.Count; L++)
            {
                NewTransformTab(false,"");
                SelectedTransformTab.Header = inAppData.transformPages[L].name;
                SelectedTransformTabTextBox.Text = inAppData.transformPages[L].text;
            }
            if (this.tabControl1.Items.Count > 0)
            {
                this.tabControl1.SelectedIndex = 0;
            }
            if (this.tabControl2.Items.Count > 0)
            {
                this.tabControl2.SelectedIndex = 0;
            }
        }

        private void mnuTransformTabNew_Click(object sender, RoutedEventArgs e)
        {
            NewTransformTab(true,"");
        }

        private void mnuTransformTabDelete_Click(object sender, RoutedEventArgs e)
        {
            MessageBoxResult result = MessageBox.Show("Are you sure you want to delete the current transform tab?", "Delete?", MessageBoxButton.OKCancel);
            if (result == MessageBoxResult.OK)
            {
                if (tabControl2.SelectedIndex > -1)
                {
                    tabControl2.Items.RemoveAt(tabControl2.SelectedIndex);
                }
            }
        }

        private void mnuRenameTab_Click(object sender, RoutedEventArgs e)
        {
            String newName = Interaction.InputBox("Enter the new name", "Enter Name", "");
            if (newName=="" | newName==null)
            {
                return;
            }
            SelectedTab.Header = newName;
        }

        private void mnuRenameTransformTab_Click(object sender, RoutedEventArgs e)
        {
            String newName = Interaction.InputBox("Enter the new name", "Enter Name", "");
            if (newName == "" | newName == null)
            {
                return;
            }
            SelectedTransformTab.Header = newName;
        }

        public List<String> SelectedTabTransforms()
        {
            String transformList = this.SelectedTransformTabTextBox.Text;
            return Miscellaneous.Split(transformList, Environment.NewLine, true);
        }

        private void btnReplace_Click(object sender, RoutedEventArgs e)
        {
            String transformMe = this.GetSelectedTextOrLine(false,true);
            if (transformMe == "" | transformMe == null)
            {
                return;
            }
            String transformedResult = SubstituteIntoExpression(transformMe);
            if (transformedResult == "" | transformedResult == null)
            {
                return;
            }
            PutTextInTextBox(transformedResult);
        }

        public static String SubstituteIntoExpression(String InExpression)
        {
            String replaceMe = Microsoft.VisualBasic.Interaction.InputBox("Enter a term to replace.","Replace Me","replaceMe");
            if (replaceMe == "" | replaceMe == null)
            {
                return null;
            }
            String replacement = Microsoft.VisualBasic.Interaction.InputBox("Enter a replacement.", "Replacement", "Replacement");
            if (replacement == null)
            {
                return null;
            }
            return InExpression.Replace(replaceMe, replacement);
        }

        //private void mnuExpandVectorEquation_Click(object sender, RoutedEventArgs e)
        //{
        //    String transformMe = this.GetSelectedTextOrLine();
        //    String vectorVariableNames = Interaction.InputBox("Enter the vector variable names.");
        //    String[] vectorVariableNamesParsed = Miscellaneous.Split(vectorVariableNames, ",", true).ToArray();
        //    String numberOfTermsToGenerateS = Interaction.InputBox("Enter the number of terms to generate.");
        //    String Operator = Interaction.InputBox("Enter the operator you want to separate the generated terms.","Enter Operator","NewLine");
        //    if (Operator == "NewLine")
        //    {
        //        Operator = Environment.NewLine;
        //    }
        //    if (Miscellaneous.IsNumeric(numberOfTermsToGenerateS) == true)
        //    {
        //        Int32 numberOfTermsToGenerateI = Convert.ToInt32(numberOfTermsToGenerateS);
        //        //String result = SymbolicComputation.Vector.ExpandVectorEquation(transformMe, numberOfEquationsToGenerateI, vectorVariableNamesParsed, Operator);
        //        //PutTextInTextBox(result);
        //    }
        //}

        public void Combinatorize(List<String> transformStrings)
        {
            String equation = this.GetSelectedTextOrLine();
            ArtificialIntelligence.AI ai;
            String[] results = TransformBranchFunctions.Combinatorize(equation, transformStrings.ToArray(),out ai);
            String result = Miscellaneous.Join(results.ToList(), Environment.NewLine);
            PutTextInTextBox(result);
        }

        public static String EvalEquations(String inRows)
        {
            List<String> rows = Miscellaneous.Split(inRows, Environment.NewLine);
            List<String> results = EvalEquations(rows.ToArray()).ToList();
            String result = String.Join(Environment.NewLine, results);
            return result;
        }

        public static String[] EvalEquations(String[] inRows)
        {
            return Functional.Maps.Map(inRows, x => RoslynEval.ScriptEval.Evaluate(Miscellaneous.AddDSuffixesToEquation(x)).ToString());
        }

        public String[] Transforms()
        {
            Int32 L;
            TextBox textBox;
            String str = "";
            for (L = 0; L < this.tabControl2.Items.Count; L++)
            {
                textBox = TransformTabTextBox(L);
                str += textBox.Text +Environment.NewLine;
            }
            return Miscellaneous.Split(str, Environment.NewLine, true).ToArray();
        }

        private void btnGraph_Click(object sender, RoutedEventArgs e)
        {
            //Viz.MainWindow lForm = new Viz.MainWindow();
            //lForm.Show();
        }

        private void HelpHelp_Click(object sender, RoutedEventArgs e)
        {
            String path=Environment.CurrentDirectory +"\\symdocs.htm";
            Process.Start(path);
        }

        private void SymHome_Click(object sender, RoutedEventArgs e)
        {
            //this will have to be swapped out when symboliccomputation.com is uploaded
            //Process.Start("http:\\symboliccomputation.com");
        }

        private void mnuTest_Click(object sender, RoutedEventArgs e)
        {
            Sym.Test.TestTransforms testForm = new Sym.Test.TestTransforms();
            testForm.Show();
        }

        private void btnSimplify_Click(object sender, RoutedEventArgs e)
        {
            Simplify();
        }

        public void Simplify()
        {
            String equation = this.GetSelectedTextOrLine();
            ArtificialIntelligence.AI ai;
            String[] results = TransformBranchFunctions.Combinatorize(equation, Transforms().ToArray(), out ai);
            PutTextInTextBox(results[0]);
        }
    }
}
